#include <iostream>
#include <fstream>
#include "StringKey.h"
#include "Dictionary.h"

using namespace std;

//*******************************

// this program is an implamentation of a dictionaty using ADT of an AVL balanced tree.
// insert and delete will trigger the balancing operations of the AVL tree.
//
// there are two ways to use this program:
// 1. give 4 arguments (using argv): txt file - workers list, int - num of workers to insert, txt file - workers to delete, int - num of workers
// 2. insert and delete workers manually using the standard std - keyboard.

//*******************************


// Read workers name from file
char* ReadWorkerName(ifstream& file)
{
	char curr; // the current char read
	char theStr[256]; // the whole string
	int length = 0;
	char* temp;
	if (!file.is_open())
		return NULL;

	file.get(curr);
	while (file.good() && curr != '\t' && curr != ' ' && curr != '\n')
	{
		theStr[length] = curr;
		length++;
		file.get(curr);
	}
	theStr[length] = '\0';
	temp = new char[length+1];
	strncpy(temp, theStr, length+1);
	return temp;
}

// Read workers name from keyboard
char* ReadWorkerName()
{
	char curr; // the current char read
	char theStr[256]; // the whole string
	char* temp;
	int length = 0;
	cout << "Please enter worker name: " ;
	curr = getc(stdin);
	while (curr != '\t' && curr != ' ' && curr != '\n')
	{
		theStr[length] = curr;
		length++;
		curr = getc(stdin);
	}
	theStr[length] = '\0';
	temp = new char[length+1];
	strncpy(temp, theStr, length+1);
	return temp;
}

// Read using files
void ReadFromFiles(char* argv[])
{
	ifstream WorkersList, WorkersNames;
	WorkersList.open ((char*)argv[2]);

	if (WorkersList.fail())
	{
		cout << "couldn\'nt open workers list file \'" << (char*)argv[2] << "\'... Bye" << endl;
		exit(1);
	}
	Dictionary myDict;

	for (int i = 0; i < atoi(argv[1]); i++)
	{
		// create new stringKey, read it's name from the file and allocate
		// enough space for the worker name
		StringKey* myKey = new StringKey; // allocate space for the new stringKey
		Worker* myWorker = new Worker(myKey); // allocate name for the worker using the stringKey
		myWorker->Read(WorkersList); // read worker from the file
		if (myKey->GetKey() && !myDict.Insert(myKey, myWorker))
		{
			cout << "Duplicate key was found, the insertion was abandoned!" << endl;
			delete(myKey);
			delete(myWorker);
		}
	}

	WorkersList.close();

	// print all data from the dictionary
	myDict.PrintDictionary();
	
	cout << endl;
	WorkersNames.open ((char*)argv[4]);
	if (WorkersNames.fail())
	{
		cout << "couldn\'nt open workers names file \'" << (char*)argv[4] << "\'... Bye" << endl;
		myDict.FreeAllElements();
		exit(1);
	}

	// find the workers
	for (int i = 0; i < atoi(argv[3]); i++)
	{
		char* name = ReadWorkerName(WorkersNames);
		if (name != "")
		{
			StringKey newKey;
			newKey.SetKey(name);
			Worker* newWorker = myDict.Find(&newKey);
			if (newWorker)
			{
				cout << "The worker popped is: "; 
				newWorker->Print();
				myDict.Delete(newWorker->GetName());
			}
			else
			{
				cout << "The Worker " << name << " wasn\'t found... delete was abandoned!" << endl;
			}
		}
		delete[] name;
	}

	WorkersNames.close();
	
	// the dictionary before quitting
	cout << endl << "The dictionary after deletes" << endl;
	myDict.PrintDictionary();

	// delete the dynamic allocations
	myDict.FreeAllElements();

}

//read input from keyboard
void ReadFromKeyboard()
{
	Dictionary myDict;
	bool read = true;
	char choice;
	char junk[256];

	cout << "Please enter some workers - name years rank: " << endl;

	while (read)
	{
		// create new stringKey, read it's name from the keyboard and allocate
		// enough space for the worker name
		StringKey* myKey = new StringKey; // allocate space for the new stringKey
		Worker* myWorker = new Worker(myKey); // allocate name for the worker using the stringKey
		myWorker->Read(); // read worker from keyboard
		if (myKey->GetKey() && !myDict.Insert(myKey, myWorker))
		{
			cout << "Duplicate key was found, the insertion was abandoned!" << endl;
			delete(myKey); // delete the allocation
			delete(myWorker);
		}
		cout << "another one (y / n)? " ;
		cin >> choice;
		choice = toupper(choice);
		read = choice == 'Y' ? true : false;
		cin.getline(junk,255); // clear redandent input
	}

	read = true; // to read workers names to delete
	// print all data from the dictionary
	myDict.PrintDictionary();
	cout << endl;
	
	cout << "Please enter some workers names to pop..." << endl;

	// find the workers
	while(read)
	{
		char* name = ReadWorkerName();
		if (name != "")
		{
			StringKey newKey;
			newKey.SetKey(name);
			Worker* newWorker = myDict.Find(&newKey);

			if (newWorker)
			{
				cout << "The worker popped is: "; 
				newWorker->Print();
				myDict.Delete(newWorker->GetName());
			}
			else
			{
				cout << "The Worker " << name << " wasn\'t found... delete was abandoned!" << endl;
			}
		}
		delete[] name;
		cout << "another one (y / n)? " ;
		cin >> choice;
		choice = toupper(choice);
		read = choice == 'Y' ? true : false;
		cin.getline(junk,255); // clear redandent input
	}
	// the dictionary before quitting
	cout << "The dictionary before quitting is :" << endl;
	myDict.PrintDictionary();

	// delete the dynamic allocations
	myDict.FreeAllElements();
}

//main
int main(int argc, char* argv[])
{

	cout  << "AVL Dictionary" << endl;
	cout  << "--------------" << endl << endl;
	if (argc == 5)
	{
		// read inputs from files
		ReadFromFiles(argv);
	}
	else
	{
		// read inputs from keyboard
		ReadFromKeyboard();
	}

	return 0;
}
